package com.yhy.common.action;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.yhy.common.config.EnvConfig;
import com.yhy.common.constants.BusSelfState;
import com.yhy.common.constants.FunProcess;
import com.yhy.common.dto.AppReturnMsg;
import com.yhy.common.dto.BaseMngDTO;
import com.yhy.common.dto.BaseMngVO;
import com.yhy.common.dto.ReturnCode;
import com.yhy.common.exception.BusinessException;
import com.yhy.common.exception.CustomRuntimeException;
import com.yhy.common.jxls.MyJxlsImportConfig;
import com.yhy.common.service.BaseMngService;
import com.yhy.common.service.BusAsposeExcelService;
import com.yhy.common.utils.BusCenterHelper;
import com.yhy.common.utils.FileUtils;
import com.yhy.common.utils.ITransationExecutor;
import com.yhy.common.utils.YhyUtils;
import com.yhy.common.vo.BusPageInfo;
import com.yhy.common.vo.SysAttachment;
import com.yhy.common.vo.SysPrintMainVO;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/*
 * Copyright (c) 2019.
 * yanghuiyuan
 */

public abstract class BaseMngAction<T extends BaseMngDTO> extends BaseAction<T> {

	protected final Logger LOGGER = LoggerFactory.getLogger(getClass());

	protected abstract BaseMngService getBaseService();

	protected AppReturnMsg toCopyCommon(HttpServletRequest request, HttpServletResponse response, T baseDTO) {
		getBaseService().toCopyData(baseDTO);
		AppReturnMsg returnMsg = new AppReturnMsg(ReturnCode.SUCCESS_CODE.getCode(),"",baseDTO,null);
		afterPublicViewInfo(baseDTO,returnMsg);
		return returnMsg;
	}

	protected AppReturnMsg toAddCommon(HttpServletRequest request, HttpServletResponse response, T baseDTO) {
		getBaseService().toAddData(baseDTO);
		AppReturnMsg returnMsg = new AppReturnMsg(ReturnCode.SUCCESS_CODE.getCode(),"",baseDTO,null);
		afterPublicViewInfo(baseDTO,returnMsg);
		return returnMsg;
	}

	protected AppReturnMsg doSubmitCommon(HttpServletRequest request, HttpServletResponse response, T baseDTO) {
		if (CollectionUtils.isEmpty(baseDTO.getIdList())) {
			throw new BusinessException("请选择提交业务记录.");
		}

		AppReturnMsg appReturnMsg = multTransactionExecute(request,response, baseDTO, new ITransationExecutor<Boolean,String>() {
			@Override
			public Boolean execute(String mainId) {
				BaseMngVO busMainData = getBaseService().findByMainId(mainId, true);
				getBaseService().doSingleSubmit(busMainData);
				return true;
			}
		});
		return appReturnMsg;
	}

	protected void afterPublicViewInfo(T baseDTO,AppReturnMsg returnMsg ) {
		BaseMngVO busMainData = baseDTO.getBusMainData();
		BusPageInfo busPageInfo = new BusPageInfo();
		if(StringUtils.isBlank(busMainData.getSelfState())) {
			busMainData.setSelfState(BusSelfState.DRAFT.getVal());
		}
		Set<String> editStats = Sets.newHashSet(BusSelfState.DRAFT.getVal(),BusSelfState.APPROVE_NOT_PASS.getVal());
		if(FunProcess.DESTORY.getVal().equals(busMainData.getFunProcess()) ||
				!editStats.contains(busMainData.getSelfState())) {
			busPageInfo.setEditable(false);
		}
		baseDTO.setBusPageInfo(busPageInfo);
    }


	@RequestMapping(value="/toView",method = RequestMethod.POST)
	@ResponseBody
	@ApiOperation(value="获取单据详细信息", notes="获取单据详细信息")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "baseDTO", value = "实体", required = true, dataType = "baseDTO")
	})
	public AppReturnMsg toView(HttpServletRequest request, HttpServletResponse response, @RequestBody T baseDTO) {
		return toViewCommon(request, response, baseDTO);
	}

	protected AppReturnMsg toViewCommon(HttpServletRequest request, HttpServletResponse response, T baseDTO) {
		getBaseService().toViewData(baseDTO);
		AppReturnMsg returnMsg = new AppReturnMsg(ReturnCode.SUCCESS_CODE.getCode(),"",baseDTO,null);
		afterPublicViewInfo(baseDTO,returnMsg);
		return returnMsg;
	}

	@RequestMapping(value="/toViewApprove",method = RequestMethod.POST)
	@ResponseBody
	@ApiOperation(value="获取单据详细信息用于审批页面", notes="获取单据详细信息用于审批页面")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "baseDTO", value = "实体", required = true, dataType = "baseDTO")
	})
	public AppReturnMsg toViewApprove(HttpServletRequest request, HttpServletResponse response, @RequestBody T baseDTO) {
		beforeOfViewApprove(baseDTO);
		AppReturnMsg returnMsg = toViewApproveCommon(request, response, baseDTO);
		return returnMsg;
	}

	protected void beforeOfViewApprove(T baseDTO) {

	}

	protected AppReturnMsg toViewApproveCommon(HttpServletRequest request, HttpServletResponse response, T baseDTO) {
		getBaseService().toViewData(baseDTO);
		AppReturnMsg returnMsg = new AppReturnMsg(ReturnCode.SUCCESS_CODE.getCode(),"",baseDTO,null);
		afterPublicViewInfo(baseDTO,returnMsg);
		return returnMsg;
	}

	protected void beforeOfSaveProcess(T baseDTO) {

	}

	protected void afterOfSaveProcess(T baseDTO) {

	}


	protected AppReturnMsg doSaveCommon(HttpServletRequest request, HttpServletResponse response, T baseDTO) {
		beforeOfSaveProcess(baseDTO);
		getBaseService().doSave(baseDTO);
		afterOfSaveProcess(baseDTO);
		return new AppReturnMsg(ReturnCode.SUCCESS_CODE.getCode(),"保存成功",baseDTO,null);
	}

	protected AppReturnMsg loadDataCommon(HttpServletRequest request, HttpServletResponse response, T baseDTO) {
		getBaseService().loadData(baseDTO);
		AppReturnMsg returnMsg = new AppReturnMsg(ReturnCode.SUCCESS_CODE.getCode(),"",baseDTO);
		afterLoadDataInfo(baseDTO,returnMsg);
		return returnMsg;
	}

	protected void afterLoadDataInfo(T baseDTO,AppReturnMsg returnMsg ) {

	}


	protected AppReturnMsg doDeleteCommon(HttpServletRequest request, HttpServletResponse response, T baseDTO) {
		if (CollectionUtils.isEmpty(baseDTO.getIdList())) {
			throw new BusinessException("删除ID不能为空.");
		}
		AppReturnMsg appReturnMsg = multTransactionExecute(request,response, baseDTO, new ITransationExecutor<Boolean,String>() {
			@Override
			public Boolean execute(String mainId) {
				BaseMngVO busMainData = getBaseService().findByMainId(mainId, true);
				getBaseService().doSingleDelete(baseDTO, busMainData);
				return true;
			}
		});
		return appReturnMsg;
	}

	/**
	 * 导出
	 */
	@RequestMapping(value="/doExport",method = {RequestMethod.POST})
	@ResponseBody
	@ApiOperation(value="数据导出", notes="数据导出")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "数据DTO对象", value = "数据DTO对象", required = false, dataTypeClass = BaseMngDTO.class),

	})
	public AppReturnMsg doExport(@RequestBody T baseDTO, HttpServletRequest request, HttpServletResponse response) {
		OutputStream outputStream = null;
		try {
			StopWatch stopWatch = null;
			if (LOGGER.isDebugEnabled()) {
				stopWatch = new StopWatch();
				stopWatch.start();
			}
			outputStream = response.getOutputStream();
			String fileName = getBaseService().processExport(baseDTO, outputStream);
			if (LOGGER.isDebugEnabled()) {
				stopWatch.stop();
				LOGGER.debug("导出总时间：{}秒", stopWatch.getTime() / 1000.00);
			}

			response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
			response.setContentType("application/octet-stream");
			outputStream.flush();
			return null;
		} catch (Exception e) {
			LOGGER.error("导出失败", e);
			String msg = StringUtils.isNotBlank(e.getMessage()) ? e.getMessage() : "导出失败";
			return new AppReturnMsg(ReturnCode.FAIL_CODE.getCode(), msg);
		} finally {
			IOUtils.closeQuietly(outputStream);
		}
	}

	@RequestMapping(value="/doImport",method = {RequestMethod.POST})
	@ResponseBody
	@ApiOperation(value="数据导入", notes="数据导入")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "数据DTO对象", value = "数据DTO对象", required = false, dataTypeClass = BaseMngDTO.class),

	})
	public AppReturnMsg doImport(HttpServletRequest request, @RequestBody T baseDTO) {
		try {
			StopWatch stopWatch = null;
			if (LOGGER.isDebugEnabled()) {
				stopWatch = new StopWatch();
				stopWatch.start();
			}
			baseDTO.setSysUser(YhyUtils.getSysUser());
			/*MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
			MultipartFile multipartFile = multipartRequest.getFileMap().values().iterator().next();
			InputStream inputStream = multipartFile.getInputStream();*/
			List<SysAttachment> sysAttachments = baseDTO.getAttachmentList();
			for (SysAttachment sysAttachment : sysAttachments) {
				InputStream inputStream =  new FileInputStream(sysAttachment.getFilePath());
				getBaseService().processImport(baseDTO, inputStream);
			}
			if (LOGGER.isDebugEnabled()) {
				stopWatch.stop();
				LOGGER.debug("导入总时间：{}秒", stopWatch.getTime() / 1000.00);
			}
			return new AppReturnMsg(ReturnCode.SUCCESS_CODE.getCode(), "导入成功");
		} catch (Exception e) {
			e.printStackTrace();
			String msg = StringUtils.isNotBlank(e.getMessage()) ? e.getMessage() : "导入失败";
			LOGGER.error("导入失败", e);
			return new AppReturnMsg(ReturnCode.FAIL_CODE.getCode(), msg);
		}
	}

	/**
	 * 下载导入模板
	 */
	@RequestMapping(value="/downloadImportTemplate",method = {RequestMethod.POST})
	@ResponseBody
	@ApiOperation(value="下载导入模板", notes="下载导入模板")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "数据DTO对象", value = "数据DTO对象", required = false, dataTypeClass = BaseMngDTO.class),

	})
	public AppReturnMsg downloadImportTemplate(HttpServletRequest request, HttpServletResponse response, @RequestBody T baseDTO) {
		OutputStream outputStream = null;
		try {
			outputStream = response.getOutputStream();
			String fileName = getBaseService().downloadImportTemplate(baseDTO, outputStream);
			response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
			response.setContentType("application/octet-stream");
			outputStream.flush();
			return null;
		} catch (Exception e) {
			LOGGER.error("下载失败", e);
			String msg = StringUtils.isNotBlank(e.getMessage()) ? e.getMessage() : "下载失败";
			return new AppReturnMsg(ReturnCode.FAIL_CODE.getCode(), msg);
		} finally {
			IOUtils.closeQuietly(outputStream);
		}
	}


	@RequestMapping(value="/doPrint",method = {RequestMethod.POST})
	@ResponseBody
	@ApiOperation(value="打印输出", notes="打印输出")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "数据DTO对象", value = "数据DTO对象", required = false, dataTypeClass = BaseMngDTO.class),

	})
	public AppReturnMsg doPrint(HttpServletRequest request, HttpServletResponse response, @RequestBody T baseDTO) {
		BufferedOutputStream bw = null;
		try {
			AppReturnMsg appReturnMsg = null;
			//将生成的excel 输出到某一文件下
			String tempFileName = YhyUtils.generateUUID();
			String uploadTempDir = EnvConfig.getValueByPropertyName("print.tmp.dir");
			String downPath = uploadTempDir + "/" + tempFileName + ".xlsx";
			File file = new File(downPath);
			if(!file.getParentFile().exists()) {
				file.getParentFile().mkdirs();
			}
			bw = new BufferedOutputStream(new FileOutputStream(downPath));
			getBaseService().processPrint(baseDTO, bw);
			IOUtils.closeQuietly(bw);

			String reportType = StringUtils.defaultIfBlank(baseDTO.getReportType(),"html").toLowerCase();
			switch (reportType) {
				case "xlsx":
					appReturnMsg = new AppReturnMsg(ReturnCode.SUCCESS_CODE.getCode(), "", "/static/print/" + tempFileName + ".xlsx");
					break;
				case "pdf":
					String pdfPath = uploadTempDir+ "/" + tempFileName + ".pdf";
					BusAsposeExcelService.excel2pdf(downPath, pdfPath);
					appReturnMsg = new AppReturnMsg(ReturnCode.SUCCESS_CODE.getCode(), "", "/static/print/" + tempFileName + ".pdf");
					//转换后删除临时 xls 文件
					FileUtils.del(downPath);
					/*response.setHeader("Content-Disposition", "attachment;filename=" + tempFileName + ".pdf");
					response.setContentType("application/octet-stream");
					//下载PDF
					//输入流：本地文件路径
					DataInputStream in = new DataInputStream(new FileInputStream(new File(pdfPath)));
					OutputStream out = response.getOutputStream();
					int bytes = 0;
					byte[] bufferOut = new byte[1024];
					while ((bytes = in.read(bufferOut)) != -1) {
						out.write(bufferOut, 0, bytes);
					}
					out.close();
					in.close();*/
					break;
				case "html":
					//文档转换
					String htmlPath = uploadTempDir+ "/" + tempFileName + ".html";
					BusAsposeExcelService.excel2html(downPath, htmlPath);
					appReturnMsg = new AppReturnMsg(ReturnCode.SUCCESS_CODE.getCode(), "", "/static/print/" + tempFileName + ".html");
					//转换后删除临时 xls 文件
					FileUtils.del(downPath);
					break;
			}
			return appReturnMsg;
		} catch (Exception e) {
			LOGGER.error("打印失败", e);
			String msg = StringUtils.isNotBlank(e.getMessage()) ? e.getMessage() : "打印失败";
			return new AppReturnMsg(ReturnCode.FAIL_CODE.getCode(), msg);
		} finally {
		}
	}

}
